#include "meshscissor.h"

namespace MeshSlice {

    MeshScissor::MeshScissor(SceneManager *pSceneMgr,
            Vector3 scissorPlaneVertices[4])
        : mpSceneMgr(pSceneMgr)
        , mPlaneVertices(scissorPlaneVertices)
    {
    }

    void MeshScissor::setScissorPlane(Vector3 scissorPlaneVertices[])
    {
        mPlaneVertices = scissorPlaneVertices;
    }

    bool MeshScissor::fuzzyContains(const QList<Vector3> &list, const Vector3 &item, const Real &tolerance)
    {
        foreach( const Vector3 &v3, list ) {
            if( item.positionEquals( v3, tolerance ) ) {
                return true;
            }
        }
        return false;
    }

    void MeshScissor::DoSplit(
            MeshPtr meshPtr,
            const Vector3 &position,
            const Quaternion &orientation,
            const Vector3 &scale,
            QList<SubMeshBlock> &pOutUpperMeshBlockList,
            QList<SubMeshBlock> &pOutLowerMeshBlockList)
    {
        pOutUpperMeshBlockList.clear();
        pOutLowerMeshBlockList.clear();

        QList<SubMeshBlock> pSubMeshBlock;
        GetMeshInformation(
                    meshPtr,
                    position,
                    orientation,
                    scale,
                    pSubMeshBlock);

        Plane pTempPlane( mPlaneVertices[0], mPlaneVertices[2], mPlaneVertices[1] );

        // slicing face
        QList<SubMeshBlock> vUpperMeshBlock;
        QList<SubMeshBlock> vLowerMeshBlock;
        QList<Vector3> vUpperVertices;
        QList<Vector3> vUpperNormals;
        QList<Vector2> vUpperTexVertices;
        QList<Vector3> vLowerVertices;
        QList<Vector3> vLowerNormals;
        QList<Vector2> vLowerTexVertices;
        QList<Vector3> vIntersectPosVerticesList;
        QList<Vector3> vIntersectNormalVerticesList;
        QList<Vector2> vIntersectTexVerticesList;

        // calculate each polygon intersect by slicing face(plane)
        for( int nMeshBlockIdx = 0; nMeshBlockIdx < pSubMeshBlock.size(); nMeshBlockIdx++ ) {
            unsigned int nTriCount = pSubMeshBlock[nMeshBlockIdx].Indices.size() / 3;
            for( unsigned int nTdx = 0; nTdx < nTriCount; nTdx++ ) {
                // Triangle ABC
                Vector3 vA = pSubMeshBlock[nMeshBlockIdx].PosVertices[(int)pSubMeshBlock[nMeshBlockIdx].Indices[(int)nTdx * 3 + 0]];
                Vector3 vB = pSubMeshBlock[nMeshBlockIdx].PosVertices[(int)pSubMeshBlock[nMeshBlockIdx].Indices[(int)nTdx * 3 + 1]];
                Vector3 vC = pSubMeshBlock[nMeshBlockIdx].PosVertices[(int)pSubMeshBlock[nMeshBlockIdx].Indices[(int)nTdx * 3 + 2]];

                Vector3 vNormalA = pSubMeshBlock[nMeshBlockIdx].NormalVertices[(int)pSubMeshBlock[nMeshBlockIdx].Indices[(int)nTdx * 3 + 0]];
                Vector3 vNormalB = pSubMeshBlock[nMeshBlockIdx].NormalVertices[(int)pSubMeshBlock[nMeshBlockIdx].Indices[(int)nTdx * 3 + 1]];
                Vector3 vNormalC = pSubMeshBlock[nMeshBlockIdx].NormalVertices[(int)pSubMeshBlock[nMeshBlockIdx].Indices[(int)nTdx * 3 + 2]];

                Vector2 vTexA = Vector2::ZERO;
                Vector2 vTexB = Vector2::ZERO;
                Vector2 vTexC = Vector2::ZERO;
                if( !pSubMeshBlock[nMeshBlockIdx].TexVertices.isEmpty() ) {
                    vTexA = pSubMeshBlock[nMeshBlockIdx].TexVertices[(int)pSubMeshBlock[nMeshBlockIdx].Indices[(int)nTdx * 3 + 0]];
                    vTexB = pSubMeshBlock[nMeshBlockIdx].TexVertices[(int)pSubMeshBlock[nMeshBlockIdx].Indices[(int)nTdx * 3 + 1]];
                    vTexC = pSubMeshBlock[nMeshBlockIdx].TexVertices[(int)pSubMeshBlock[nMeshBlockIdx].Indices[(int)nTdx * 3 + 2]];
                }

                // triangle point A->B
                Vector3 vABIntersectPoint = Vector3::ZERO;
                Vector2 vABIntersectTexPoint = Vector2::ZERO;
                Vector3 vABIntersectNormal = Vector3::ZERO;
                bool bIsABIntersect = CheckIntersectPointPolygonBetweenLine(
                            mPlaneVertices,
                            vA,
                            vB,
                            vTexA,
                            vTexB,
                            vNormalA,
                            vNormalB,
                            vABIntersectPoint,
                            vABIntersectNormal,
                            vABIntersectTexPoint);
                if( bIsABIntersect ) {
                    bool isExist = fuzzyContains( vIntersectPosVerticesList, vABIntersectPoint, 0.0001f );
                    if( !isExist ) {
                        vIntersectPosVerticesList.push_back(vABIntersectPoint);
                        vIntersectTexVerticesList.push_back(vABIntersectTexPoint);
                        vIntersectNormalVerticesList.push_back(vABIntersectNormal);
                    }
                }

                // triangle point B->C
                Vector3 vBCIntersectPoint = Vector3::ZERO;
                Vector2 vBCIntersectTexPoint = Vector2::ZERO;
                Vector3 vBCIntersectNormal = Vector3::ZERO;
                bool bIsBCIntersect = CheckIntersectPointPolygonBetweenLine(
                            mPlaneVertices,
                            vB,
                            vC,
                            vTexB,
                            vTexC,
                            vNormalB,
                            vNormalC,
                            vBCIntersectPoint,
                            vBCIntersectNormal,
                            vBCIntersectTexPoint);
                if( bIsBCIntersect ) {
                    bool isExist = fuzzyContains( vIntersectPosVerticesList, vBCIntersectPoint, 0.0001f );
                    if( !isExist ) {
                        vIntersectPosVerticesList.push_back(vBCIntersectPoint);
                        vIntersectTexVerticesList.push_back(vBCIntersectTexPoint);
                        vIntersectNormalVerticesList.push_back(vBCIntersectNormal);
                    }
                }

                // triangle point C->A
                Vector3 vCAIntersectPoint = Vector3::ZERO;
                Vector2 vCAIntersectTexPoint = Vector2::ZERO;
                Vector3 vCAIntersectNormal = Vector3::ZERO;
                bool bIsCAIntersect = CheckIntersectPointPolygonBetweenLine(
                            mPlaneVertices, vC, vA, vTexC, vTexA,
                            vNormalC, vNormalA,
                            vCAIntersectPoint,
                            vCAIntersectNormal,
                            vCAIntersectTexPoint);
                if( bIsCAIntersect ) {
                    bool isExist = fuzzyContains( vIntersectPosVerticesList, vCAIntersectPoint, 0.0001f );
                    if( !isExist ) {
                        vIntersectPosVerticesList.push_back(vCAIntersectPoint);
                        vIntersectTexVerticesList.push_back(vCAIntersectTexPoint);
                        vIntersectNormalVerticesList.push_back(vCAIntersectNormal);
                    }
                }

                // if this triangle is no intersected.
                if( !bIsABIntersect && !bIsBCIntersect && !bIsCAIntersect )
                {
                    // decide the triangle location by triangle point A
                    Plane::Side enSide = pTempPlane.getSide(vA);
                    if( enSide == Plane::POSITIVE_SIDE ) {
                        vUpperVertices.push_back(vA);
                        vUpperVertices.push_back(vB);
                        vUpperVertices.push_back(vC);

                        vUpperTexVertices.push_back(vTexA);
                        vUpperTexVertices.push_back(vTexB);
                        vUpperTexVertices.push_back(vTexC);

                        vUpperNormals.push_back(vNormalA);
                        vUpperNormals.push_back(vNormalB);
                        vUpperNormals.push_back(vNormalC);

                    }else if( enSide == Plane::NEGATIVE_SIDE) {
                        vLowerVertices.push_back(vA);
                        vLowerVertices.push_back(vB);
                        vLowerVertices.push_back(vC);

                        vLowerTexVertices.push_back(vTexA);
                        vLowerTexVertices.push_back(vTexB);
                        vLowerTexVertices.push_back(vTexC);

                        vLowerNormals.push_back(vNormalA);
                        vLowerNormals.push_back(vNormalB);
                        vLowerNormals.push_back(vNormalC);
                    }

                }else {
                    // intersected(AB or BC or CA)
                    // calculate upper polygon info and lower polygon info
                    if( !bIsABIntersect && bIsBCIntersect && bIsCAIntersect ) {
                        if( pTempPlane.getSide(vC) == Plane::POSITIVE_SIDE ) {
                            // Position Vertex
                            vUpperVertices.push_back(vC);
                            vUpperVertices.push_back(vCAIntersectPoint);
                            vUpperVertices.push_back(vBCIntersectPoint);

                            vLowerVertices.push_back(vCAIntersectPoint);
                            vLowerVertices.push_back(vA);
                            vLowerVertices.push_back(vB);
                            vLowerVertices.push_back(vCAIntersectPoint);
                            vLowerVertices.push_back(vB);
                            vLowerVertices.push_back(vBCIntersectPoint);

                            // Texture Vertex
                            vUpperTexVertices.push_back(vTexC);
                            vUpperTexVertices.push_back(vCAIntersectTexPoint);
                            vUpperTexVertices.push_back(vBCIntersectTexPoint);

                            vLowerTexVertices.push_back(vCAIntersectTexPoint);
                            vLowerTexVertices.push_back(vTexA);
                            vLowerTexVertices.push_back(vTexB);
                            vLowerTexVertices.push_back(vCAIntersectTexPoint);
                            vLowerTexVertices.push_back(vTexB);
                            vLowerTexVertices.push_back(vBCIntersectTexPoint);

                            // Нормали
                            vUpperNormals.push_back(vNormalC);
                            vUpperNormals.push_back(vCAIntersectNormal);
                            vUpperNormals.push_back(vBCIntersectNormal);

                            vLowerNormals.push_back(vCAIntersectNormal);
                            vLowerNormals.push_back(vNormalA);
                            vLowerNormals.push_back(vNormalB);
                            vLowerNormals.push_back(vCAIntersectNormal);
                            vLowerNormals.push_back(vNormalB);
                            vLowerNormals.push_back(vBCIntersectNormal);

                        }else {
                            vLowerVertices.push_back(vC);
                            vLowerVertices.push_back(vCAIntersectPoint);
                            vLowerVertices.push_back(vBCIntersectPoint);

                            vUpperVertices.push_back(vCAIntersectPoint);
                            vUpperVertices.push_back(vA);
                            vUpperVertices.push_back(vB);
                            vUpperVertices.push_back(vCAIntersectPoint);
                            vUpperVertices.push_back(vB);
                            vUpperVertices.push_back(vBCIntersectPoint);

                            vLowerTexVertices.push_back(vTexC);
                            vLowerTexVertices.push_back(vCAIntersectTexPoint);
                            vLowerTexVertices.push_back(vBCIntersectTexPoint);

                            vUpperTexVertices.push_back(vCAIntersectTexPoint);
                            vUpperTexVertices.push_back(vTexA);
                            vUpperTexVertices.push_back(vTexB);
                            vUpperTexVertices.push_back(vCAIntersectTexPoint);
                            vUpperTexVertices.push_back(vTexB);
                            vUpperTexVertices.push_back(vBCIntersectTexPoint);

                            vLowerNormals.push_back(vNormalC);
                            vLowerNormals.push_back(vCAIntersectNormal);
                            vLowerNormals.push_back(vBCIntersectNormal);

                            vUpperNormals.push_back(vCAIntersectNormal);
                            vUpperNormals.push_back(vNormalA);
                            vUpperNormals.push_back(vNormalB);
                            vUpperNormals.push_back(vCAIntersectNormal);
                            vUpperNormals.push_back(vNormalB);
                            vUpperNormals.push_back(vBCIntersectNormal);
                        }

                    }else if( bIsABIntersect && bIsBCIntersect && !bIsCAIntersect ) {
                        if( pTempPlane.getSide(vB) == Plane::POSITIVE_SIDE ) {
                            vUpperVertices.push_back(vABIntersectPoint);
                            vUpperVertices.push_back(vB);
                            vUpperVertices.push_back(vBCIntersectPoint);

                            vLowerVertices.push_back(vC);
                            vLowerVertices.push_back(vA);
                            vLowerVertices.push_back(vABIntersectPoint);
                            vLowerVertices.push_back(vC);
                            vLowerVertices.push_back(vABIntersectPoint);
                            vLowerVertices.push_back(vBCIntersectPoint);

                            vUpperTexVertices.push_back(vABIntersectTexPoint);
                            vUpperTexVertices.push_back(vTexB);
                            vUpperTexVertices.push_back(vBCIntersectTexPoint);

                            vLowerTexVertices.push_back(vTexC);
                            vLowerTexVertices.push_back(vTexA);
                            vLowerTexVertices.push_back(vABIntersectTexPoint);
                            vLowerTexVertices.push_back(vTexC);
                            vLowerTexVertices.push_back(vABIntersectTexPoint);
                            vLowerTexVertices.push_back(vBCIntersectTexPoint);

                            vUpperNormals.push_back(vABIntersectNormal);
                            vUpperNormals.push_back(vNormalB);
                            vUpperNormals.push_back(vBCIntersectNormal);

                            vLowerNormals.push_back(vNormalC);
                            vLowerNormals.push_back(vNormalA);
                            vLowerNormals.push_back(vABIntersectNormal);
                            vLowerNormals.push_back(vNormalC);
                            vLowerNormals.push_back(vABIntersectNormal);
                            vLowerNormals.push_back(vBCIntersectNormal);

                        }else {
                            vLowerVertices.push_back(vABIntersectPoint);
                            vLowerVertices.push_back(vB);
                            vLowerVertices.push_back(vBCIntersectPoint);

                            vUpperVertices.push_back(vC);
                            vUpperVertices.push_back(vA);
                            vUpperVertices.push_back(vABIntersectPoint);
                            vUpperVertices.push_back(vC);
                            vUpperVertices.push_back(vABIntersectPoint);
                            vUpperVertices.push_back(vBCIntersectPoint);

                            vLowerTexVertices.push_back(vABIntersectTexPoint);
                            vLowerTexVertices.push_back(vTexB);
                            vLowerTexVertices.push_back(vBCIntersectTexPoint);

                            vUpperTexVertices.push_back(vTexC);
                            vUpperTexVertices.push_back(vTexA);
                            vUpperTexVertices.push_back(vABIntersectTexPoint);
                            vUpperTexVertices.push_back(vTexC);
                            vUpperTexVertices.push_back(vABIntersectTexPoint);
                            vUpperTexVertices.push_back(vBCIntersectTexPoint);

                            vLowerNormals.push_back(vABIntersectNormal);
                            vLowerNormals.push_back(vNormalB);
                            vLowerNormals.push_back(vBCIntersectNormal);

                            vUpperNormals.push_back(vNormalC);
                            vUpperNormals.push_back(vNormalA);
                            vUpperNormals.push_back(vABIntersectNormal);
                            vUpperNormals.push_back(vNormalC);
                            vUpperNormals.push_back(vABIntersectNormal);
                            vUpperNormals.push_back(vBCIntersectNormal);
                        }

                    }else if( bIsABIntersect && !bIsBCIntersect && bIsCAIntersect ) {
                        if( pTempPlane.getSide(vA) == Plane::POSITIVE_SIDE ) {
                            vUpperVertices.push_back(vCAIntersectPoint);
                            vUpperVertices.push_back(vA);
                            vUpperVertices.push_back(vABIntersectPoint);

                            vLowerVertices.push_back(vC);
                            vLowerVertices.push_back(vCAIntersectPoint);
                            vLowerVertices.push_back(vABIntersectPoint);
                            vLowerVertices.push_back(vC);
                            vLowerVertices.push_back(vABIntersectPoint);
                            vLowerVertices.push_back(vB);

                            vUpperTexVertices.push_back(vCAIntersectTexPoint);
                            vUpperTexVertices.push_back(vTexA);
                            vUpperTexVertices.push_back(vABIntersectTexPoint);

                            vLowerTexVertices.push_back(vTexC);
                            vLowerTexVertices.push_back(vCAIntersectTexPoint);
                            vLowerTexVertices.push_back(vABIntersectTexPoint);
                            vLowerTexVertices.push_back(vTexC);
                            vLowerTexVertices.push_back(vABIntersectTexPoint);
                            vLowerTexVertices.push_back(vTexB);

                            vUpperNormals.push_back(vCAIntersectNormal);
                            vUpperNormals.push_back(vNormalA);
                            vUpperNormals.push_back(vABIntersectNormal);

                            vLowerNormals.push_back(vNormalC);
                            vLowerNormals.push_back(vCAIntersectNormal);
                            vLowerNormals.push_back(vABIntersectNormal);
                            vLowerNormals.push_back(vNormalC);
                            vLowerNormals.push_back(vABIntersectNormal);
                            vLowerNormals.push_back(vNormalB);

                        }else {
                            vLowerVertices.push_back(vCAIntersectPoint);
                            vLowerVertices.push_back(vA);
                            vLowerVertices.push_back(vABIntersectPoint);

                            vUpperVertices.push_back(vC);
                            vUpperVertices.push_back(vCAIntersectPoint);
                            vUpperVertices.push_back(vABIntersectPoint);
                            vUpperVertices.push_back(vC);
                            vUpperVertices.push_back(vABIntersectPoint);
                            vUpperVertices.push_back(vB);

                            vLowerTexVertices.push_back(vCAIntersectTexPoint);
                            vLowerTexVertices.push_back(vTexA);
                            vLowerTexVertices.push_back(vABIntersectTexPoint);

                            vUpperTexVertices.push_back(vTexC);
                            vUpperTexVertices.push_back(vCAIntersectTexPoint);
                            vUpperTexVertices.push_back(vABIntersectTexPoint);
                            vUpperTexVertices.push_back(vTexC);
                            vUpperTexVertices.push_back(vABIntersectTexPoint);
                            vUpperTexVertices.push_back(vTexB);

                            vLowerNormals.push_back(vCAIntersectNormal);
                            vLowerNormals.push_back(vNormalA);
                            vLowerNormals.push_back(vABIntersectNormal);

                            vUpperNormals.push_back(vNormalC);
                            vUpperNormals.push_back(vCAIntersectNormal);
                            vUpperNormals.push_back(vABIntersectNormal);
                            vUpperNormals.push_back(vNormalC);
                            vUpperNormals.push_back(vABIntersectNormal);
                            vUpperNormals.push_back(vNormalB);
                        }
                    }
                }
            }

            // Create the render object by upper slicing mesh info
            if( vUpperVertices.size() >= 3 )
            {
                SubMeshBlock pUpperMeshBlock;
                pUpperMeshBlock.MaterialName = pSubMeshBlock[nMeshBlockIdx].MaterialName;
                for( int nVdx = 0; nVdx < vUpperVertices.size(); nVdx++ ) {
                    pUpperMeshBlock.PosVertices.push_back(vUpperVertices[nVdx]);
                    pUpperMeshBlock.TexVertices.push_back(vUpperTexVertices[nVdx]);
                    pUpperMeshBlock.NormalVertices.push_back(vUpperNormals[nVdx]);
                }

                for( int nVdx = 0; nVdx < vUpperVertices.size(); nVdx++ ) {
                    pUpperMeshBlock.Indices.push_back((unsigned int)nVdx);
                }

                vUpperMeshBlock.push_back(pUpperMeshBlock);

                vUpperVertices.clear();
                vUpperTexVertices.clear();
                vUpperNormals.clear();
            }

            // Create the render object by lower slicing mesh info
            if( vLowerVertices.size() >= 3 ) {
                SubMeshBlock pLowerMeshBlock;
                pLowerMeshBlock.MaterialName = pSubMeshBlock[nMeshBlockIdx].MaterialName;
                for( int nVdx = 0; nVdx < vLowerVertices.size(); nVdx++ ) {
                    pLowerMeshBlock.PosVertices.push_back(vLowerVertices[nVdx]);
                    pLowerMeshBlock.TexVertices.push_back(vLowerTexVertices[nVdx]);
                    pLowerMeshBlock.NormalVertices.push_back(vLowerNormals[nVdx]);
                }

                for( int nVdx = 0; nVdx < vLowerVertices.size(); nVdx++ ) {
                    pLowerMeshBlock.Indices.push_back((unsigned int)nVdx);
                }

                vLowerMeshBlock.push_back(pLowerMeshBlock);

                vLowerVertices.clear();
                vLowerTexVertices.clear();
                vLowerNormals.clear();
            }
        }

        // Вырезать, связанный с ним
        SubMeshBlock pUpperSplitFaceBlock, pLowerSplitFaceBlock;
        CalculateSplitFaceVertex(vIntersectPosVerticesList, vIntersectNormalVerticesList, pUpperSplitFaceBlock, pLowerSplitFaceBlock);
        if( !pUpperSplitFaceBlock.isNull() ) {
            if( vUpperMeshBlock.size() >= 1)
                pUpperSplitFaceBlock.MaterialName = vUpperMeshBlock[0].MaterialName;
            vUpperMeshBlock.push_back(pUpperSplitFaceBlock);
        }

        if( !pLowerSplitFaceBlock.isNull() ) {
            if( vLowerMeshBlock.size() >= 1)
                pLowerSplitFaceBlock.MaterialName = vLowerMeshBlock[0].MaterialName;
            vLowerMeshBlock.push_back(pLowerSplitFaceBlock);
        }

        // for physx mesh
        pOutUpperMeshBlockList.append(vUpperMeshBlock);
        pOutLowerMeshBlockList.append(vLowerMeshBlock);
    }

    void MeshScissor::GetMeshInformation(MeshPtr mesh, const Vector3 &position, const Quaternion &orientation, const Vector3 &scale, QList<SubMeshBlock> &pOutSubMeshBlock)
    {
        SubMeshBlock pSharedSubMeshBlock; // Для суб-сетки вершин, используя общий

        // Обход подсетку получить информацию.
        for( unsigned short nIdx = 0; nIdx < mesh->getNumSubMeshes(); nIdx++ ) {
            SubMesh *submesh = mesh->getSubMesh(nIdx);

            // Если вы используете общий вершины
            if( submesh->useSharedVertices ) {
                // Если вы цените общую инициализацию буфера вершин
                VertexData *pVertexData = mesh->sharedVertexData;
                pSharedSubMeshBlock.MaterialName = submesh->getMaterialName();
                pSharedSubMeshBlock.PosVertices.clear();
                pSharedSubMeshBlock.NormalVertices.clear();
                pSharedSubMeshBlock.TexVertices.clear();
                pSharedSubMeshBlock.Indices.clear();

                // Сохраняем положение
                const VertexElement *pPosElement = pVertexData->vertexDeclaration->findElementBySemantic(VES_POSITION);
                if( NULL != pPosElement ) {
                    HardwareVertexBufferSharedPtr pPosBuffer = pVertexData->vertexBufferBinding->getBuffer(pPosElement->getSource());
                    char* pPosVertex = (char*)pPosBuffer->lock(HardwareBuffer::HBL_READ_ONLY);
                    float* pPosReal;
                    for( size_t j = 0; j < pVertexData->vertexCount; ++j, pPosVertex += pPosBuffer->getVertexSize() ) {
                        pPosElement->baseVertexPointerToElement(pPosVertex, &pPosReal);
                        Vector3 pt = Vector3(pPosReal[0], pPosReal[1], pPosReal[2]);
                        pt = orientation * (pt * scale) + position;
                        pSharedSubMeshBlock.PosVertices.push_back( pt );
                    }
                    pPosBuffer->unlock();
                }

                // Сохраняем нормали
                const VertexElement *pNormalElement = pVertexData->vertexDeclaration->findElementBySemantic(VES_NORMAL);
                if( NULL != pNormalElement ) {
                    HardwareVertexBufferSharedPtr pNormalBuffer = pVertexData->vertexBufferBinding->getBuffer(pNormalElement->getSource());
                    char* pNormalVertex = (char*)pNormalBuffer->lock(HardwareBuffer::HBL_READ_ONLY);
                    float* pNormalReal;
                    for( size_t j = 0; j < pVertexData->vertexCount; ++j, pNormalVertex += pNormalBuffer->getVertexSize())
                    {
                        pNormalElement->baseVertexPointerToElement(pNormalVertex, &pNormalReal);
                        Vector3 pt = Vector3(pNormalReal[0], pNormalReal[1], pNormalReal[2]);
                        pt = orientation * (pt * scale) + position;
                        pSharedSubMeshBlock.NormalVertices.push_back( pt );
                    }
                    pNormalBuffer->unlock();
                }

                // Сохраняем текстурные координаты
                const VertexElement *pTexElement = pVertexData->vertexDeclaration->findElementBySemantic(VES_TEXTURE_COORDINATES);
                if( NULL != pTexElement ) {
                    HardwareVertexBufferSharedPtr pTexBuffer = pVertexData->vertexBufferBinding->getBuffer(pTexElement->getSource());
                    char* pTexVertex = (char*)pTexBuffer->lock(HardwareBuffer::HBL_READ_ONLY);
                    float* pTexReal;
                    for( size_t j = 0; j < pVertexData->vertexCount; ++j, pTexVertex += pTexBuffer->getVertexSize())
                    {
                        pTexElement->baseVertexPointerToElement(pTexVertex, &pTexReal);
                        Vector2 tx = Vector2(pTexReal[0], pTexReal[1]);
                        pSharedSubMeshBlock.TexVertices.push_back( tx );
                    }
                    pTexBuffer->unlock();
                }

                // Использование общих вершин индекса сетки к югу от хранения
                //unsigned int numTriangles = submesh->indexData->indexCount / 3;
                HardwareIndexBufferSharedPtr iBuffer = submesh->indexData->indexBuffer;
                bool use32BitIndex = (iBuffer->getType() == HardwareIndexBuffer::IT_32BIT);
                unsigned int* pLong = (unsigned int*)iBuffer->lock(HardwareBuffer::HBL_READ_ONLY);
                unsigned short* pShort = (unsigned short*)pLong;
                if( use32BitIndex ) {
                    for( size_t k = 0; k < submesh->indexData->indexCount; ++k)
                        pSharedSubMeshBlock.Indices.push_back((quint64)pLong[k]);
                }else {
                    for( size_t k = 0; k < submesh->indexData->indexCount; ++k)
                        pSharedSubMeshBlock.Indices.push_back((quint64)pShort[k]);
                }
                iBuffer->unlock();
            }
            else // Если вы не используете общий вершины
            {
                // Сетка вершину данных является использование суб-
                const VertexData *pSubMeshVertexData = submesh->vertexData;
                // Суб-сетка информационный блок инициализации
                SubMeshBlock pSubMeshBlock;
                pSubMeshBlock.MaterialName = submesh->getMaterialName();
                pSubMeshBlock.PosVertices.clear();
                pSubMeshBlock.TexVertices.clear();
                pSubMeshBlock.NormalVertices.clear();
                pSubMeshBlock.Indices.clear();

                // Пик положение
                const VertexElement *pPosElement = pSubMeshVertexData->vertexDeclaration->findElementBySemantic(VES_POSITION);
                if( NULL != pPosElement ) {
                    HardwareVertexBufferSharedPtr pPosBuffer = pSubMeshVertexData->vertexBufferBinding->getBuffer(pPosElement->getSource());
                    char* pPosVertex = (char*)pPosBuffer->lock(HardwareBuffer::HBL_READ_ONLY);
                    float* pPosReal;
                    for( size_t j = 0; j < pSubMeshVertexData->vertexCount; ++j, pPosVertex += pPosBuffer->getVertexSize())
                    {
                        pPosElement->baseVertexPointerToElement(pPosVertex, &pPosReal);
                        Vector3 pt = Vector3(pPosReal[0], pPosReal[1], pPosReal[2]);
                        pt = orientation * (pt * scale) + position;
                        pSubMeshBlock.PosVertices.push_back( pt );
                    }
                    pPosBuffer->unlock();
                }

                {
                    const VertexElement *pNormalElement = pSubMeshVertexData->vertexDeclaration->findElementBySemantic(VES_NORMAL);
                    if( NULL != pNormalElement ) {
                        HardwareVertexBufferSharedPtr pNormalBuffer = pSubMeshVertexData->vertexBufferBinding->getBuffer(pNormalElement->getSource());
                        char* pNormalVertex = (char*)pNormalBuffer->lock(HardwareBuffer::HBL_READ_ONLY);
                        float* pNormalReal;
                        for( size_t j = 0; j < pSubMeshVertexData->vertexCount; ++j, pNormalVertex += pNormalBuffer->getVertexSize())
                        {
                            pNormalElement->baseVertexPointerToElement(pNormalVertex, &pNormalReal);
                            Vector3 pt = Vector3(pNormalReal[0], pNormalReal[1], pNormalReal[2]);
                            pt = orientation * (pt * scale) + position;
                            pSubMeshBlock.NormalVertices.push_back( pt );
                        }
                        pNormalBuffer->unlock();
                    }
                }

                // текстур из вершинных
                const VertexElement *pTexElement = pSubMeshVertexData->vertexDeclaration->findElementBySemantic(VES_TEXTURE_COORDINATES);
                if( NULL != pTexElement ) {
                    HardwareVertexBufferSharedPtr pTexBuffer = pSubMeshVertexData->vertexBufferBinding->getBuffer(pTexElement->getSource());
                    char* pTexVertex = (char*)pTexBuffer->lock(HardwareBuffer::HBL_READ_ONLY);
                    float* pTexReal;
                    for( size_t j = 0; j < pSubMeshVertexData->vertexCount; ++j, pTexVertex += pTexBuffer->getVertexSize())
                    {
                        pTexElement->baseVertexPointerToElement(pTexVertex, &pTexReal);
                        Vector2 tx = Vector2(pTexReal[0], pTexReal[1]);
                        pSubMeshBlock.TexVertices.push_back(tx);
                    }
                    pTexBuffer->unlock();
                }

                // Индекс информация
                //unsigned int numTriangles = submesh->indexData->indexCount / 3;
                HardwareIndexBufferSharedPtr iBuffer = submesh->indexData->indexBuffer;
                bool use32BitIndex = (iBuffer->getType() == HardwareIndexBuffer::IT_32BIT);
                unsigned int* pLong = (unsigned int*)iBuffer->lock(HardwareBuffer::HBL_READ_ONLY);
                unsigned short* pShort = (unsigned short*)pLong;
                if( use32BitIndex ) {
                    for( size_t k = 0; k < submesh->indexData->indexCount; ++k)
                        pSubMeshBlock.Indices.push_back((quint64)pLong[k]);
                }else {
                    for( size_t k = 0; k < submesh->indexData->indexCount; ++k)
                        pSubMeshBlock.Indices.push_back((quint64)pShort[k]);
                }
                iBuffer->unlock();

                pOutSubMeshBlock.push_back(pSubMeshBlock);
            }
        }

        if( !pSharedSubMeshBlock.isNull() )
            pOutSubMeshBlock.push_back(pSharedSubMeshBlock);
    }

    ManualObject *MeshScissor::makeObject(const QList<SubMeshBlock> &meshBlockList, const String &materialName)
    {
        if( meshBlockList.isEmpty() ) return NULL;

        ManualObject *result = mpSceneMgr->createManualObject();
        result->begin( materialName, RenderOperation::OT_TRIANGLE_LIST );
        foreach( const SubMeshBlock &block, meshBlockList ) {
            for( int index = 0; index < block.PosVertices.size(); ++index ) {
                const Vector3 &pos = block.PosVertices.at(index);
                result->position( pos );

                const Vector3 &normal = block.NormalVertices.at(index);
                result->normal( normal.normalisedCopy() );

                const Vector2 &uv = block.TexVertices.at(index);
                result->textureCoord( uv );

                const quint64 &i = block.Indices.at(index);
                result->index( (uint32)i );
            }
        }
        result->end();

        return result;
    }

    void MeshScissor::GetMeshInformation(
            MeshPtr mesh,
            unsigned int &vertex_count,
            Vector3 *vertices,
            Vector2 *texvertices,
            unsigned int &index_count,
            quint64 *indices,
            const Vector3 &position,
            const Quaternion &orientation,
            const Vector3 &scale)
    {
        bool added_shared = false;
        unsigned int current_offset = 0;
        unsigned int shared_offset = 0;
        unsigned int next_offset = 0;
        unsigned int index_offset = 0;

        vertex_count = index_count = 0;

        for( unsigned short i = 0; i < mesh->getNumSubMeshes(); ++i)
        {
            SubMesh *submesh = mesh->getSubMesh(i);
            if( submesh->useSharedVertices)
            {
                if( !added_shared)
                {
                    vertex_count += mesh->sharedVertexData->vertexCount;
                    added_shared = true;
                }
            }
            else
            {
                vertex_count += submesh->vertexData->vertexCount;
            }

            index_count += submesh->indexData->indexCount;
        }

        vertices = new Vector3[vertex_count];
        texvertices = new Vector2[vertex_count];
        indices = new quint64[index_count];
        added_shared = false;

        for( unsigned short i = 0; i < mesh->getNumSubMeshes(); ++i)
        {
            SubMesh *submesh = mesh->getSubMesh(i);
            const VertexData *vertex_data = submesh->useSharedVertices ? mesh->sharedVertexData : submesh->vertexData;

            if( !submesh->useSharedVertices || (submesh->useSharedVertices && !added_shared))
            {
                if( submesh->useSharedVertices)
                {
                    added_shared = true;
                    shared_offset = current_offset;
                }

                // расположение
                const VertexElement *posElem = vertex_data->vertexDeclaration->findElementBySemantic(VES_POSITION);
                if( NULL != posElem ) {
                    HardwareVertexBufferSharedPtr vbuf = vertex_data->vertexBufferBinding->getBuffer(posElem->getSource());

                    char* vertex = (char*)vbuf->lock(HardwareBuffer::HBL_READ_ONLY);
                    float* pReal;

                    for( size_t j = 0; j < vertex_data->vertexCount; ++j, vertex += vbuf->getVertexSize())
                    {
                        posElem->baseVertexPointerToElement(vertex, &pReal);
                        Vector3 pt(pReal[0], pReal[1], pReal[2]);
                        vertices[current_offset + j] = (orientation * (pt * scale)) + position;
                    }
                    vbuf->unlock();
                }

                // текстура
                const VertexElement *texElem = vertex_data->vertexDeclaration->findElementBySemantic(VES_TEXTURE_COORDINATES);
                if( NULL != texElem ) {
                    HardwareVertexBufferSharedPtr vtexbuf = vertex_data->vertexBufferBinding->getBuffer(texElem->getSource());

                    char* texture = (char*)vtexbuf->lock(HardwareBuffer::HBL_READ_ONLY);
                    float* pTexReal;

                    for( size_t j = 0; j < vertex_data->vertexCount; ++j, texture += vtexbuf->getVertexSize())
                    {
                        texElem->baseVertexPointerToElement(texture, &pTexReal);
                        Vector2 tx(pTexReal[0], pTexReal[1]);
                        texvertices[current_offset + j] = tx;
                    }
                    vtexbuf->unlock();
                }

                next_offset += vertex_data->vertexCount;
            }

            const IndexData *index_data = submesh->indexData;
            //unsigned int numTris = index_data->indexCount / 3;
            HardwareIndexBufferSharedPtr ibuf = index_data->indexBuffer;

            bool use32bitindexes = (ibuf->getType() == HardwareIndexBuffer::IT_32BIT);

            unsigned int* pLong = (unsigned int*)ibuf->lock(HardwareBuffer::HBL_READ_ONLY);
            unsigned short* pShort = (unsigned short*)pLong;
            unsigned int offset = submesh->useSharedVertices ? shared_offset : current_offset;
            if( use32bitindexes)
            {
                for( size_t k = 0; k < index_data->indexCount; ++k)
                {
                    indices[index_offset++] = (quint64)pLong[k] + (quint64)offset;
                }
            }
            else
            {
                for( size_t k = 0; k < index_data->indexCount; ++k)
                {
                    indices[index_offset++] = (quint64)pShort[k] + (quint64)offset;
                }
            }
            ibuf->unlock();
            current_offset = next_offset;
        }
    }

    void MeshScissor::CalculateSplitFaceVertex(
            QList<Vector3> &vIntersectPosVerticesList,
            QList<Vector3> &vIntersectNormalVerticesList,
            SubMeshBlock &pUpperSplitFaceBlock,
            SubMeshBlock &pLowerSplitFaceBlock)
    {
        if( vIntersectPosVerticesList.size() >= 3)
        {
            pUpperSplitFaceBlock.MaterialName = "BaseWhiteNoLighting";
            pUpperSplitFaceBlock.PosVertices.clear();
            pUpperSplitFaceBlock.TexVertices.clear();
            pUpperSplitFaceBlock.Indices.clear();
            pUpperSplitFaceBlock.NormalVertices.clear();

            pLowerSplitFaceBlock.MaterialName = "BaseWhiteNoLighting";
            pLowerSplitFaceBlock.PosVertices.clear();
            pLowerSplitFaceBlock.TexVertices.clear();
            pLowerSplitFaceBlock.Indices.clear();
            pLowerSplitFaceBlock.NormalVertices.clear();

            // center point
            Vector3 vCenterPoint = Vector3::ZERO;
            Vector3 vCenterNormal = Vector3::ZERO;
            AxisAlignedBox aabb;
            for( int nVdx = 0; nVdx < vIntersectPosVerticesList.size(); nVdx++)
                aabb.merge(vIntersectPosVerticesList[nVdx]);
            //vCenterPoint = pTempPlane.ProjectVector(aabb.Center) + (-pTempPlane.normal * pTempPlane.d);
            vCenterPoint = aabb.getCenter();

            AxisAlignedBox aabbN;
            for( int nVdx = 0; nVdx < vIntersectNormalVerticesList.size(); nVdx++)
                aabbN.merge(vIntersectNormalVerticesList[nVdx]);
            //vCenterPoint = pTempPlane.ProjectVector(aabb.Center) + (-pTempPlane.normal * pTempPlane.d);
            vCenterNormal = aabbN.getCenter();

            // В качестве опорных точек 0-й поколения
            for( int nVdxA = 0; nVdxA < vIntersectPosVerticesList.size(); nVdxA++)
            {
                for( int nVdxB = nVdxA + 1; nVdxB < vIntersectPosVerticesList.size(); nVdxB++)
                {
                    Vector3 vCenterToCurrentA = vIntersectPosVerticesList[nVdxA] - vCenterPoint;
                    vCenterToCurrentA.normalise();
                    Vector3 vCenterToCurrentB = vIntersectPosVerticesList[nVdxB] - vCenterPoint;
                    vCenterToCurrentB.normalise();

                    float fAngleA = Math::ATan2(vCenterToCurrentA.z, vCenterToCurrentA.x).valueDegrees();
                    float fAngleB = Math::ATan2(vCenterToCurrentB.z, vCenterToCurrentB.x).valueDegrees();
                    if( fAngleA > fAngleB)
                    {
                        Vector3 vTemp = vIntersectPosVerticesList[nVdxA];
                        vIntersectPosVerticesList[nVdxA] = vIntersectPosVerticesList[nVdxB];
                        vIntersectPosVerticesList[nVdxB] = vTemp;

                        vTemp = vIntersectNormalVerticesList[nVdxA];
                        vIntersectNormalVerticesList[nVdxA] = vIntersectNormalVerticesList[nVdxB];
                        vIntersectNormalVerticesList[nVdxB] = vTemp;
                    }
                }
            }

            // Цзы треугольник к центру от каждой точки генерируется.
            vIntersectPosVerticesList.push_back(vIntersectPosVerticesList[0]);
            vIntersectNormalVerticesList.push_back(vIntersectNormalVerticesList[0]);
            unsigned int nUdx = 0, nLdx = 0;
            for( int nVdx = 0; nVdx < vIntersectPosVerticesList.size() - 1; nVdx++)
            {
                Vector3 vA = vCenterPoint;
                Vector3 vB = vIntersectPosVerticesList[nVdx + 0];
                Vector3 vC = vIntersectPosVerticesList[nVdx + 1];

                Vector3 vAN = vCenterNormal;
                Vector3 vBN = vIntersectNormalVerticesList[nVdx + 0];
                Vector3 vCN = vIntersectNormalVerticesList[nVdx + 1];

                pUpperSplitFaceBlock.PosVertices.push_back(vA);
                pUpperSplitFaceBlock.PosVertices.push_back(vB);
                pUpperSplitFaceBlock.PosVertices.push_back(vC);
                pUpperSplitFaceBlock.NormalVertices.push_back(vAN);
                pUpperSplitFaceBlock.NormalVertices.push_back(vBN);
                pUpperSplitFaceBlock.NormalVertices.push_back(vCN);
                pUpperSplitFaceBlock.TexVertices.push_back(Vector2::ZERO);
                pUpperSplitFaceBlock.TexVertices.push_back(Vector2::ZERO);
                pUpperSplitFaceBlock.TexVertices.push_back(Vector2::ZERO);
                pUpperSplitFaceBlock.Indices.push_back(nUdx++);
                pUpperSplitFaceBlock.Indices.push_back(nUdx++);
                pUpperSplitFaceBlock.Indices.push_back(nUdx++);

                pLowerSplitFaceBlock.PosVertices.push_back(vA);
                pLowerSplitFaceBlock.PosVertices.push_back(vC);
                pLowerSplitFaceBlock.PosVertices.push_back(vB);
                pLowerSplitFaceBlock.NormalVertices.push_back(vAN);
                pLowerSplitFaceBlock.NormalVertices.push_back(vBN);
                pLowerSplitFaceBlock.NormalVertices.push_back(vCN);
                pLowerSplitFaceBlock.TexVertices.push_back(Vector2::ZERO);
                pLowerSplitFaceBlock.TexVertices.push_back(Vector2::ZERO);
                pLowerSplitFaceBlock.TexVertices.push_back(Vector2::ZERO);
                pLowerSplitFaceBlock.Indices.push_back(nLdx++);
                pLowerSplitFaceBlock.Indices.push_back(nLdx++);
                pLowerSplitFaceBlock.Indices.push_back(nLdx++);
            }
        }
    }

    bool MeshScissor::CheckIntersectPointPolygonBetweenLine(
            Vector3 vTempPlanePoint[4],
            const Vector3 &vA,
            const Vector3 &vB,
            const Vector2 &vTexA,
            const Vector2 &vTexB,
            const Vector3 &vNormA,
            const Vector3 &vNormB,
            Vector3 &vABIntersectPoint,
            Vector3 &vABIntersectNormal,
            Vector2 &vABTexVertex)
    {
        bool isIntersect = false;

        // Вектор из B к
        Vector3 vDir = vB - vA;
        float fLength = vDir.length();
        vDir.normalise();

        // Луч, направленный от А до Б и задней части самолета и расстояния определить, является ли тест пересечения определяет, является ли Крест
        Ray pRay(vA, vDir);

        QList<Vector3> pPlanePointList;
        pPlanePointList << vTempPlanePoint[0];
        pPlanePointList << vTempPlanePoint[2];
        pPlanePointList << vTempPlanePoint[1];
        pPlanePointList << vTempPlanePoint[0];
        pPlanePointList << vTempPlanePoint[3];
        pPlanePointList << vTempPlanePoint[2];
        for( int nIdx = 0; nIdx < 2; nIdx++)
        {
            Vector3 vPlanePointA = pPlanePointList[nIdx * 3 + 0];
            Vector3 vPlanePointB = pPlanePointList[nIdx * 3 + 1];
            Vector3 vPlanePointC = pPlanePointList[nIdx * 3 + 2];

            std::pair<bool,float> bResult = Math::intersects(pRay, vPlanePointA, vPlanePointB, vPlanePointC, true, true);
            if( bResult.first == true)
            {
                // Тест улице пересечения результат меньше, чем расстояние АВ gyochadoem
                if( bResult.second < fLength)
                {
                    vABIntersectPoint = pRay.getPoint(bResult.second);
                    isIntersect = true;

                    // исчисление размера сбора
                    // направление текстуры
                    Vector2 vTexDir = vTexB - vTexA;
                    float fTexLength = vTexDir.length();
                    vTexDir.normalise();

                    float fRatio = bResult.second / fLength;
                    float fTexRatioLength = fTexLength * fRatio; // Расстояние рассчитывается по соотношению исходной текстуры
                    vABTexVertex = vTexA + (vTexDir * fTexRatioLength);

                    vABIntersectNormal = Math::lerp<Vector3>( vNormA, vNormB, fRatio );

                    break;
                }
            }
        }

        return isIntersect;
    }

} // namespace MeshSlice
